﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.IO;

using System.Runtime.Serialization.Formatters.Binary;
using System.Xml.Serialization;

using Sintaxe;
using Sintaxe.Instrucoes;
using Sintaxe.Tokens;
using Sintaxe.Simbolos;
using Objects_J5;

/*
 * 
 * A classe é responsavel para montar programas
 * em linguagem de montador, produzindo objetos relocaveis e
 * demais artefatos
 * 
 */

namespace Montador
{
    public struct OpcMont
    {
        public bool Debug;  // produzir mensagens de debug
    }

    public class Montador
    {
        // Controle de operação do montador =======================
        // Montador é operado como singleton
        //
        public string TipoProcPadrao;
        // ################################# opções faltam

        // Programa sob processamento ======================
        //
        public ProgMon PROG;  // o programa átual e o estado de manipulação dele
        private Instrucao[] INST;    // cópia parcial do programa
        private Operacao[] OPS;       // cópia parcial do programa

        // Resultados de operações, particularmento do montar =======================
        //
        public string ItemProtocolo;
        private tblMensagens MENS = new tblMensagens();
        private tblLista LIST = new tblLista();
        public uint NumErros
        {
            get { return MENS.NumErrs(); }
        }
        public String Lista
        {
            get
            {
                if (LIST == null) return "";
                return LIST.RepVisual();
            }
        }

        private ColSimbo SIM;
        private ObjRelo RELO;
        public bool TemObjRelo;

        // Sintaxe especifica do montador (mas não do processador)
        //
            Diretor DI = new Diretor();

        // Constructor ==================================
        //
        public Montador(string prmProcessador)
        {
            TipoProcPadrao = prmProcessador;
        }

        // Processamento de programas fonte ===============================
        //
        public void NovoProg()
        {
            // instanciar novo programa, para processador padrão
            // o tipo do processador será devolvido no parâmetro out
            // Deixa notícia em ItemProtocolo se consegue, lança exceção se não.

            UtilDescartar();
            PROG = new ProgMon(TipoProcPadrao);
        }
        public void DescartarProg()
        {
            // descartar programa átual
            // consegue se não tem prog. átual, se é persistente e congruente
            // deixa notície em elementoProtocolo

            if (PROG == null) return;
            UtilDescartar();
            ItemProtocolo = "Programa átual fechado.";
        }
        public bool LerProg(BinaryReader brFonte)
        {
            // instanciar novo programa, baseado em arquivo
            // overload simplificado para mon
            // retorna booleana indicando se foi executado
            // Deixa notícia em ItemProtocolo se consegue, lança exceção se não.

            UtilDescartar();
            PROG = new ProgMon(brFonte);
            FileStream fsx = brFonte.BaseStream as FileStream;
            ItemProtocolo = String.Format("Abriu programa {0}", fsx.Name);
            return true;
        }
        public void GravProg(BinaryWriter bwFonte)
        {
            // gravar o programa para um arquivo
            // Deixa notícia em ItemProtocolo se consegue, lança exceção se não!

            FileStream fsx = bwFonte.BaseStream as FileStream;
            PROG.Gravar(bwFonte);
            ItemProtocolo = String.Format("Programa gravado para arquivo {0}.", fsx.Name);
        }
        private void UtilDescartar()
        {
            // funcionalidade comum de Novo, Descartar e Ler. Não gera item protocolo, os callers devem gerar
            // descartar prog átual, se houve.
            // arrumar dados relacionados

            if (PROG == null) return;

            PROG = null;
        }

        // Funcionamento de montar com método principal e métodos de passos individuais
        //
        //
        public void Montar(OpcMont OPM)
        {
            // função principal do montador
            string ss;
            try
            {
                Preparar(OPM);
                MontarVerti(OPM);
                MontarHori(OPM);
                OrgaSimbo(OPM);
                OrgaFixup(OPM);
                // OrgaProps(OPM);  Vou realizar mais tarde

                TemObjRelo = false;
                MontarCabeca(OPM);
                MontarBinario(OPM);
                MontarFixup(OPM);
                // MontarCompat(OPM); Vou realizar mais tarde
                MontarSimbo(OPM);
                MontarString(OPM);
                TemObjRelo = true;

                ss = "Montar terminou con êxito.";
                MENS.I(null, String.Format("{0} {1}", DateTime.Now, ss));
                ItemProtocolo = ss;
            }
            catch (ApplicationException ae)
            {
                ss = String.Format("Montar terminou com erro na fase {0}.", ae.Message);
                MENS.I(null, String.Format("{0} {1}", DateTime.Now, ss));
                ItemProtocolo = ss;
            }
            catch (Exception ex)
            {
                ss = String.Format("Montar terminou com exceção inesperada {0}.", ex.Message);
                MENS.I(null, String.Format("{0} {1}", DateTime.Now, ss));
                ItemProtocolo = ss;
            }
        }
        private void Preparar(OpcMont prmOPM)
        {
            // preparando estruturas para acesso mais facil.
            // mapeando opcodes
            // este aumenta o consumo da memória (considerado sem maldade) mas 
            // evita replicar código complicado em luguraes múltiplos.
            IProcessador PROC;
            DataRow rr = null;
            Instrucao ii;
            Operacao oo;
            String ss;
            Tokens tt;


            // vigilânça sanitária
            if (PROG == null) throw new ArgumentNullException("PROG não deve ser null");
            if (PROG.Linhas == null) throw new ArgumentNullException("Linhas não deve ser null");

            // Inicializar estruturas de resultado
            //
            MENS.Rows.Clear();
            MENS.I(null, String.Format("{0} Início de Montar",DateTime.Now));
            SIM = new ColSimbo();
            RELO = null;  // instanciado somente depois montagem com sucesso


            // programa vazio?
            if (PROG.Linhas.Rows.Count == 0)
            {
                MENS.E(null, "Programa não tem linhas.");
                throw new ApplicationException("Preparar");
            }

            // tamanho
            int Tam = PROG.Linhas.Rows.Count;
            INST = new Instrucao[Tam];
            OPS = new Operacao[Tam];

            // Acesso à informação do processador alvo
            PROC = Portfolio.objProc(PROG.TipoProc);
            tt = PROC.Mnemos();

            // copiar instruções e operações
            for (int ll = 0; ll < Tam; ll++)
            {
                try
                {
                    // copiar instruções
                    rr = PROG.Linhas.Rows[ll];
                    ii = (Instrucao)rr["Instrucao"];
                    INST[ll] = ii;


                    // Mapear operações. O mapeamento pode ser nas Diretivas ou nos Mnemos
                    ss = ii.Operacao;
                    oo = null;
                    if ((ss != null) && (ss != ""))  // else, não é diretiva ou instrução da maquina
                    {
                        if (tt.Existe(ss)) oo = (Operacao)tt.Item(ss);  // temos um Mnemo
                        else if (Diretor.Diretivas.Existe(ss)) oo = (Operacao)Diretor.Diretivas.Item(ss); // temos uma diretiva
                        if (oo == null) MENS.E((uint)ll + 1, "Opcode desconhecido: " + ss);  // temos algo ilegal
                        else OPS[ll] = oo;
                    }
                    
                }                
                catch (Exception ex)
                {
                    // exceções inesperados
                    MENS.E((uint)rr["NumLin"], String.Format("Exeção inesperada : {0}.", ex.Message));
                }
            }
            if (prmOPM.Debug) MENS.D(null, String.Format("Preparar processou {0} linhas.", Tam));
            if (MENS.NumErrs() > 0) throw new ApplicationException("Preparar");
        }
        private void MontarVerti(OpcMont prmOPM)
        {

            // montar verticalmente cada linha
            IProcessador PROC = Portfolio.objProc(PROG.TipoProc);
            int Tam = OPS.Length;
            UInt64 edcAtual = 0;

            for (int ll = 0; ll < Tam; ll++)
            {
                try
                {
                    // aplicar método específico de montagem vertical
                    if (OPS[ll] != null) edcAtual = OPS[ll].MontarVert(edcAtual, ref INST[ll]);
                }
                catch (ApplicationException ae)
                {
                    // exceçoes esperados no montar, típicamente erros de endereçamento
                    // continuar de montar, mas lembre!
                    MENS.E((uint)(ll+1), ae.Message);
                }
                catch (Exception ex)
                {
                    // exceções inesperados
                    MENS.E((uint)(ll + 1), ex.Message);
                    throw new ApplicationException("MontarVerti", ex);
                }
            }
            if (prmOPM.Debug)
            {
                MENS.D(null, String.Format("MontarVerti processou {0} linhas.", Tam));
                MENS.D(null, String.Format("Primeiro endereço : {0:X4}",
                    INST[0].edcAtual));
                MENS.D(null, String.Format("Último endereço: {0:X4}", 
                    INST[INST.Length-1].edcProx-1));
            }

            // testar transbordo de endereço
            UInt64 maxObj = INST[INST.Length - 1].edcProx - 1;
            if (maxObj > PROC.EndMax())
                MENS.E(null, String.Format(
                    "Ultimo endereço no objeto, 0x{0:X} maior que endereço máximo do processador, 0x{1:X}.",
                    maxObj,
                    PROC.EndMax()));

            if (MENS.NumErrs() > 0) throw new ApplicationException("MontarVerti");
        }
        private void MontarHori(OpcMont prmOPM)
        {
            /* Invoca a rotina de montagem horizontal em cada instrução.
             * Este produz a representação binária de 0 ou mais bytes.
             * Este pode produzir uma definição de símbolo, uma propriedade e/ou um Fixup.
             */

            for (int ll = 0; ll < INST.Length; ll++)
            {
                try
                {
                    OPS[ll].MontarHori(ref INST[ll]);
                }
                catch (ApplicationException ae)
                {
                    // exceçoes esperados no montar.
                    // continuar de montar, mas lembre!
                    MENS.E((uint)(ll + 1), ae.Message);
                }
                catch (Exception ex)
                {
                    // exceções inesperados. Morte súbito para não obfuscar a situação
                    MENS.E((uint)(ll + 1), ex.Message);
                    throw new ApplicationException("MontarHori", ex);
                }
            }
            if (prmOPM.Debug) MENS.D(null, String.Format("MontHori processou {0} linhas.", INST.Length));
            if (MENS.NumErrs() > 0) throw new ApplicationException("MontHori");

        }
        private void OrgaSimbo(OpcMont prmOPM)
        {
            // Organisar os símbolos em tabela SimDefs 
            // Vincular símbolos com endereços. Fiscalizar semántica estática
            //
            // Procedimento em 3 fases:
            // 1. colocar definições de rótulos da linha
            // 2. modificar propriedades deles seguindo diretivas
            // 3. colocar referências externas não definidas localmente (import labels)

            Valor vv;
            SimboloFonte ff;

            // Fase 1-3: colocar definições de símbolos
            for (int fase = 1; fase <= 3; fase++)
            {
                for (int ll = 0; ll < INST.Length; ll++)
                {
                    try
                    {
                        switch (fase)
                        {
                            case 1:
                                // colocar definições de rótulos da linha e da diretiva
                                vv = new Valor(INST[ll].Rotulo);
                                ff = INST[ll].DefSim;

                                if (ff != null)
                                {
                                    // diretivas forneçem símbolos assim
                                    if (vv.Tipo != TipoVal.Vazio) throw new ApplicationException("Esta diretiva não é compativel com rótula da linha.");
                                    if (ff.Tipo == TipoSimbo.Programa) SIM.InsSimDef(1, ff, (uint)(ll + 1));
                                }
                                else
                                {
                                    // instruções podem ter rótulos simbólicos
                                    if (vv.Tipo == TipoVal.Vazio) continue;  // nada a fazer para esta instrução
                                    if (vv.Tipo == TipoVal.Ilegal) throw new ApplicationException(vv.Mensagem);
                                    if (vv.Tipo != TipoVal.Ident) throw new ApplicationException("Rótulo da linha deve ser um identificador.");
                                    
                                    // aqui sabemos que temos um rótulo bem formado.
                                    // Vamos transforma-lo em um símbolo e guarda-lo na tabela.
                                    ff = new SimboloFonte(vv.Lexema);
                                    ff.Localizar(INST[ll].edcAtual);
                                    SIM.InsSimDef(1, ff, (uint)(ll + 1));
                                }
                                break;
                            case 2:
                                // modificar propriedades deles seguindo diretivas
                                ff = INST[ll].DefSim;
                                if (ff != null) SIM.InsSimDef(2, ff, (uint)(ll + 1));
                                break;
                            case 3:
                                // colocar referências externas não definidas localmente (import labels)
                                 ff = INST[ll].DefSim;
                                if (ff != null) SIM.InsSimDef(3, ff, (uint)(ll + 1));
                                break;
                           default:
                                break;
                        }

                    }
                    catch (ApplicationException ae)
                    {
                        // exceçoes esperados no montar.
                        // continuar de montar, mas lembre!
                        MENS.E((uint)(ll + 1), ae.Message);
                    }
                    catch (ConstraintException)
                    {
                        // exceçoes esperados no montar.
                        // continuar de montar, mas lembre!
                        MENS.E((uint)(ll + 1), "Símbolo duplamente definido.");
                    }
                    catch (Exception ex)
                    {
                        // exceções inesperados. Morte súbito para não obfuscar a situação
                        MENS.E((uint)(ll + 1), ex.Message);
                        throw new ApplicationException("OrgaSimbo", ex);
                    }
                } // for ll
            }  // for fase

            if (prmOPM.Debug)
            {
                MENS.D(null, String.Format("OrgaSimbo processou {0} linhas.", INST.Length));
                MENS.D(null, String.Format("OrgaSimbo processou {0} definições de símbolos.", SIM.SimDefs.Rows.Count));
                MENS.D(null, String.Format("OrgaSimbo processou {0} referências para símbolos.", SIM.SimRefs.Rows.Count));
            }
            if (MENS.NumErrs() > 0) throw new ApplicationException("OrgaSimbo");
        }
        private void OrgaFixup(OpcMont prmOPM)
        {
            // tratar os fixups de instruções

            // contar os fixups de varias classes
            int numLiteral = 0;
            int numLocal = 0;
            int numExterno = 0;
            FixupFonte ff;
            SimboloFonte si;

            for (int ll = 0; ll < INST.Length; ll++)
            {
                try
                {
                    ff = INST[ll].Fixup;

                    // 1. Tem Fixup?
                    if (ff == null) continue;

                    // 2. Tem Fixup referindo um símbolo?
                    if (ff.Simbolico)
                    {
                        si = SIM.InsSimRef(ff, ll+1);  // problemas apareceriam como exceção
                        if (si.Definido)
                        {
                            // temos endereço local. Vamos passar para a instrução
                            numLocal++;
                            ObjRelo.SetEdc(ref INST[ll].RepBin, si.edcLocal, ff.Distanca, ff.Tamanho);
                            ff.Simbolico = false;
                        }
                        else
                        {
                            // temos rótulo importado. O fixup fica simbólico
                            numExterno++;
                        }
                    }
                    else // Fixup literal. Tem endereço local e fica com este
                    {
                        numLiteral++;
                    }
                }
                catch (ApplicationException ae)
                {
                    // exceçoes esperados no montar.
                    // continuar de montar, mas lembre!
                    MENS.E((uint)(ll + 1), ae.Message);
                }
                catch (Exception ex)
                {
                    // exceções inesperados. Morte súbito para não obfuscar a situação
                    MENS.E((uint)(ll + 1), ex.Message);
                    throw new ApplicationException("OrgaFixup", ex);
                }
            } // for ll

            if (prmOPM.Debug)
            {
                MENS.D(null, String.Format("OrgaFixup processou {0} linhas.", INST.Length));
                MENS.D(null, String.Format("OrgaFixup processou {0} rótulos literais numéricos.", numLiteral));
                MENS.D(null, String.Format("OrgaFixup processou {0} rótulos simbólicos definidos localmente", numLocal));
                MENS.D(null, String.Format("OrgaFixup processou {0} rótulos simbólicos externos.", numExterno));
            }
            if (MENS.NumErrs() > 0) throw new ApplicationException("OrgaFixup");
        }
        private void MontarCabeca(OpcMont OPM)
        {
            // Gerar novo objeto relocavel e atribuir alguns
            // valores no cabecote
            RELO = new ObjRelo();
            RELO.IdProc = Portfolio.objProc(PROG.TipoProc).Identificacao();
            RELO.Relocavel = true;
            DataRow[] SimbolosStart = SIM.SimDefs.Select("Start = True");
            RELO.TemStart = (SimbolosStart.Length > 0);
            if (RELO.TemStart) RELO.edcStart = (UInt64)SimbolosStart[0]["Endereco"];
        }
        private void MontarBinario(OpcMont OPM)
        {
            // Colocar as palavras de programa para dentro do objeto
        }
        private void MontarFixup(OpcMont OPM)
        {
            // Colocar os fixups para dentro do objeto
        }
        private void MontarCompat(OpcMont OPM)
        {
            // Vou realizar mais tarde
            // colocar a lista de precessadores compatives para dentro do objeto
        }
        private void MontarSimbo(OpcMont OPM)
        {
            // Colocar a lista de símbolos para dentro de objeto
        }
        private void MontarString(OpcMont OPM)
        {
            // Colocar os strings de símbolos (e outros??) para dentro de objeto
        }


        // Processamento de resultados com método principal e métodos de passos individuais
        //
        //
        public void ListarResultados(optLista prmOpt)
        {
            LIST.Clear();
            if (prmOpt.Protocolo) ListarProtocolo();
            if (prmOpt.Fonte) ListarFonte(prmOpt.ComObs);
            if (prmOpt.Observacoes) ListarObservacoes();
            if (prmOpt.Simbolos) ListarSimbolos(prmOpt.ComXref);
            // ListarFixups
            // Listar Compats
            if (prmOpt.Objeto) ListarObjeto(prmOpt.ComFonte);
        }
        public void ListarCabSecao(Secao prmSecao, string prmTitulo, ref int intPos)
        {
            // inserir linha cabeçalho
            DataRow ll = LIST.NewRow();
            ll["Secao"] = (int)prmSecao;
            ll["Posicao"] = intPos++;
            ll["Col1"] = String.Format("============  {0} ===============", prmTitulo);
            ll["Col2"] = "";
            ll["Col3"] = "";
            LIST.Rows.Add(ll);
        }
        public void ListarLinhaVazia(Secao prmSecao, ref int intPos)
        {
            // inserir linha vazia
            DataRow ll = LIST.NewRow();
            ll["Secao"] = (int)prmSecao;
            ll["Posicao"] = intPos++;
            ll["Col1"] = "";
            ll["Col2"] = "";
            ll["Col3"] = "";
            LIST.Rows.Add(ll);
        }
        public void ListarProtocolo()
        {
            int intPos = 0;
            ListarCabSecao(Secao.Prot, "Protocolo", ref intPos);

            var pp = from item in this.MENS.AsEnumerable()
                     where item.Field<CatMens>("Categoria") == CatMens.Protocolo
                     select item;

            foreach (DataRow rr in pp)
            {
                int intLin = (int)rr["Linha"];
                string strTxt = (string)rr["Mensagem"];
                string strLin = (intLin > 0) ? intLin.ToString() : "";

                DataRow ll = this.LIST.NewRow();
                ll["Secao"] = (int)Secao.Prot;
                ll["Posicao"] = intPos++;
                ll["Col1"] = strLin;
                ll["Col2"] = strTxt;
                ll["Col3"] = "";
                this.LIST.Rows.Add(ll);
            }

            ListarLinhaVazia(Secao.Prot, ref intPos);
        }
        public void ListarFonte(bool ComObs)
        {
            int intPos = 0;
            ListarCabSecao(Secao.Fonte, "Fonte", ref intPos);

            for (int pl = 0; pl < PROG.Linhas.Rows.Count; pl++) // for clássico pq. preciso o número da linha
            {
                string strTxt = (string)PROG.Linhas.Rows[pl]["RepVis"];
                string strLin = (pl + 1).ToString();

                DataRow ll = this.LIST.NewRow();
                ll["Secao"] = (int)Secao.Fonte;
                ll["Posicao"] = intPos++;
                ll["Col1"] = strLin;
                ll["Col2"] = strTxt;
                ll["Col3"] = "";
                this.LIST.Rows.Add(ll);
                if ((ComObs) & (LIST != null))
                {
                    // tem observações para esta linha de código fonte?
                    var obs = from item in MENS.AsEnumerable()
                              where ((item.Field<CatMens>("Categoria") == CatMens.Erro)
                                      | (item.Field<CatMens>("Categoria") == CatMens.Alerta)
                                      | (item.Field<CatMens>("Categoria") == CatMens.Debug)
                                     )
                                     & (item.Field<int>("Linha") == pl + 1)
                              select item;

                    foreach (DataRow oo in obs)
                    {
                        CatMens cc = (CatMens)oo["Categoria"];
                        string strId = cc.ToString();
                        strTxt = (string)oo["Mensagem"];

                        ll = this.LIST.NewRow();
                        ll["Secao"] = (int)Secao.Fonte;
                        ll["Posicao"] = intPos++;
                        ll["Col1"] = "";  // observações intercaladas não mostram número da linha mas apareçem apos da linha observada
                        ll["Col2"] = strId;
                        ll["Col3"] = strTxt;
                        this.LIST.Rows.Add(ll);
                    }
                }
            }

            ListarLinhaVazia(Secao.Fonte, ref intPos);
        }
        public void ListarObservacoes()
        {
            int intPos = 0;
            ListarCabSecao(Secao.Obs, "Observações", ref intPos);

            var obs = from item in MENS.AsEnumerable()
                      where ((item.Field<CatMens>("Categoria") == CatMens.Erro)
                              | (item.Field<CatMens>("Categoria") == CatMens.Alerta)
                              | (item.Field<CatMens>("Categoria") == CatMens.Debug)
                              )
                              & (item.Field<int>("Linha") <= 0)
                      select item;

            foreach (DataRow oo in obs)
            {
                string strTxt = (string)oo["Mensagem"];
                CatMens cc = (CatMens)oo["Categoria"];
                string strId = cc.ToString();

                DataRow ll = this.LIST.NewRow();
                ll["Secao"] = (int)Secao.Obs;
                ll["Posicao"] = intPos++;
                ll["Col1"] = "";  // observações intercaladas não mostram número da linha mas apareçem apos da linha observada
                ll["Col2"] = strId;
                ll["Col3"] = strTxt;
                this.LIST.Rows.Add(ll);
            }

            ListarLinhaVazia(Secao.Obs, ref intPos);
        }
        public void ListarSimbolos(bool ComXref)
        {
            int intPos = 0;
            ListarCabSecao(Secao.Simbo, "Símbolos", ref intPos);

            string strLex;
            string strTipo;
            string strExt;
            string strLoc;
            string strStart;
            string strEdc;
            string strLin;
            DataRow ll;

            // listar símobolos em ordem alfabética
            DataView dvSimb = SIM.SimDefs.DefaultView;
            dvSimb.Sort = "Lexema asc, Tipo asc";

            for (int ii = 0; ii < dvSimb.Count; ii++)
            {
                // colocar parâmetros do símbolo
                strLex = (string)dvSimb[ii]["Lexema"];
                strTipo = ((TipoSimbo)dvSimb[ii]["Tipo"]).ToString();
                strExt = ((bool)dvSimb[ii]["Externo"]) ? "externo, " : "";
                strLin = String.Format("{0}", (UInt32)dvSimb[ii]["Linha"]);
                strLoc = ((bool)dvSimb[ii]["Definido"]) ? "def.local, " : "";
                strStart = ((bool)dvSimb[ii]["Start"]) ? "start, " : "";
                strEdc = ((bool)dvSimb[ii]["Vinculado"]) ?
                    String.Format("Endereço {0:X16}", (UInt64)dvSimb[ii]["Endereco"]) : "";

                // primeira linha da listagem do símbolo
                ll = LIST.NewRow();
                ll["Secao"] = (int)Secao.Simbo;
                ll["Posicao"] = intPos++;
                ll["Col1"] = "";
                ll["Col2"] = strTipo;
                ll["Col3"] = strLex;
                this.LIST.Rows.Add(ll);

                // segunda linha da listagem do símbolo
                ll = LIST.NewRow();
                ll["Secao"] = (int)Secao.Simbo;
                ll["Posicao"] = intPos++;
                ll["Col1"] = "";
                ll["Col2"] = "";
                ll["Col3"] = strExt + strStart + strLoc + strEdc;
                this.LIST.Rows.Add(ll);
            }

            ListarLinhaVazia(Secao.Simbo, ref intPos);

            // if (ComXref) ...
        }
        public void ListarFixups()
        {
            int intPos = 0;
            ListarCabSecao(Secao.Simbo, "Fixups", ref intPos);

            //....

            ListarLinhaVazia(Secao.Simbo, ref intPos);
        }
        public void ListarObjeto(bool ComFonte)
        {
            int intPos = 0;
            ListarCabSecao(Secao.Objeto, "Objeto", ref intPos);

            //....

            ListarLinhaVazia(Secao.Objeto, ref intPos);
        }

        // Gravar Resultados para arquivos
        //
        //
        public void GravLista(StreamWriter swrLista)
        {
        }
        public void GravObjRelo(BinaryWriter bwObjRelo)
        {
            // gravar o objeto relocavel para um arquivo
            // Deixa notícia em ItemProtocolo se consegue, lança exceção se não!

            FileStream fsx = bwObjRelo.BaseStream as FileStream;
            RELO.Gravar(bwObjRelo);
            ItemProtocolo = String.Format("Objeto relocavel gravado para arquivo {0}.", fsx.Name);
            fsx.Close();
        }
    }
}
